/*
 * Copyright 2012 Alain Pannetrat (L1L1@gmx.com)
 * 
 * This file is part of cookie-miner.
 * 
 * cookie-miner is free software: you can redistribute it and/or modify 
 * it under the terms of the GNU General Public License as published by 
 * the Free Software Foundation, either version 3 of the License, or 
 * (at your option) any later version.
 * 
 * cookie-miner is distributed in the hope that it will be useful, but 
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 
 * General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License 
 * along with cookie-miner. If not, see http://www.gnu.org/licenses/.
 *
 * @version: $Id$
 *
 */
#include "effective_tld.h"
#include <string>
#include <vector>
#include "dictionary.h"
#include "log_facility.h"

class DomainNameParser {
	public:
		bool load(const std::string& s);
		const std::string& suffix();
		bool shift();
		bool unshift();
	private:
		std::string _suffix;
		std::vector<std::string> _labels;
		unsigned pos;
};

// dictionary<string::std>

bool DomainNameParser::load(const std::string& s)
{
    std::string label;
    size_t ppos;
    size_t cpos;

    _labels.clear();
    pos = 0;
    _suffix.clear();

    if (s.size()==0)
	return false;

    if (s[0]=='.')
	ppos = 1;
    else
	ppos = 0;
    while ((cpos=s.find('.',ppos))!=std::string::npos)
    {
	_labels.push_back(s.substr(ppos,cpos-ppos));
	ppos = cpos + 1;
    }
    _labels.push_back(s.substr(ppos));
    _suffix = s; 
    return true;
}

const std::string& DomainNameParser::suffix()
{
    if (_labels.size()==0)
	return _suffix;

    _suffix = _labels[_labels.size()-1];

    if (_labels.size()<2)
	return _suffix;

    for (unsigned i = _labels.size()-1;i>pos;i--)
	_suffix = _labels[i-1] + "." + _suffix;

    return _suffix;		
}

bool DomainNameParser::unshift()
{
    if (pos==0) return false; 	
    pos--;
    return true;
}

bool DomainNameParser::shift()
{
	if (pos==_labels.size()-1) return false;
	pos++;
	return true;
}

Dictionary<int> rules_exceptions;
Dictionary<int> rules_star;
Dictionary<int> rules_default;

#include "effective_tld_names.inc"
bool effective_tld_load()
{
    const char *rule;
    unsigned i = 0;	

    while ((rule = EFFECTIVE_TLD_PREFIX_RULES[i++])!=NULL)
    {
	switch (rule[0]) {
	    case '!':
		rules_exceptions.set(rule+1,1);
		break;	
	    case '*':	
		rules_star.set(rule+2,1);
		break;	
	    case '.':	
		rules_default.set(rule+1,1);
		break;	
	    default:	
		rules_default.set(rule,1);
	}	
    }
    return true;
}

bool preload_effective_tld_rules = effective_tld_load();

std::string effective_domain(const std::string& candidate)
{
	DomainNameParser dnp;
	
	if (candidate.find_first_not_of("0123456789.")==std::string::npos) 
		return candidate;

	dnp.load(candidate);
		
	do
	{
		const std::string& suffix = dnp.suffix();

		if (rules_exceptions.exists(suffix))
		{
			return dnp.suffix();
		}
		if (rules_star.exists(suffix))
		{
			dnp.unshift();
			dnp.unshift();	
			return dnp.suffix();
		}		
		if (rules_default.exists(suffix))
		{
			dnp.unshift();
			return dnp.suffix();	
		}
	} 
	while (dnp.shift());
 
	dnp.unshift();	
	return dnp.suffix();
}

#include <stdio.h>

Dictionary<int> rules_tpl;
int tpl_load(const char *tpl_file)
{
	int count = 0;
	char *p;
	char *q;
	char buf[250];
	FILE *TPL = fopen(tpl_file,"r");

	if (TPL==NULL) return -1;

	while (fgets(buf,250,TPL))
	{
		buf[249]=0;
		if (buf[0]=='-' && buf[1]=='d')
		{
			p=buf+3;
			while (*p==32) p++;
			q=p;
			while (*q>32) q++;
			*q=0;
			rules_tpl.set(p,1);
			count++;	
		}
	}
	return count;
}

bool tpl_match(const std::string& candidate)
{
	DomainNameParser dnp;
		
	dnp.load(candidate);
	
	do
	{
		const std::string& suffix = dnp.suffix();

		if (rules_tpl.exists(suffix))
		{
			//logger.message(logger.LOG_DEBUG,"Matching TPL %s: success",suffix.c_str());	
			return true;
		}
		//else
		//	logger.message(logger.LOG_DEBUG,"Matching TPL %s: failure",suffix.c_str());	

	} 
	while (dnp.shift());
 
	return false;
}

#ifdef TEST_EFFECTIVE_TLD
#include <iostream>
int main(int argc, char **argv)
{
	for (unsigned i=1;i<argc;i++)
	{
		std::cout << argv[i] << " => " << effective_domain(argv[i]) << "\n";
	}
}
#endif
